#pragma once

// -----------------------------------------------------------------------------
#include "Win32.Diagnostics.Result.h"

#include <malloc.h>
#include <TCHAR.h>
#include <strsafe.h>

namespace Kif
{
namespace Win32
{

/// <summary>Provide a memory allocation and release class</summary>
class Memory
{
private:
   Kif::Win32::Diagnostics::Result lastResult;

public:

   /// <summary>Allocate needed space for buffer</summary>
   /// <param name="sizeInBytes">size to alloc in bytes</param>
   /// <returns>returns requested buffer else NULL</returns>
   static inline void *alloc(size_t sizeInBytes)
   {
      return(::malloc(sizeInBytes));
   }  // end of alloc

   /// <summary>Allocate needed space for buffer. You must make sure that the
   /// size does include the bytes necessary for the null char at the end of
   /// the string</summary>
   /// <param name="sizeInBytes">size to alloc in bytes</param>
   /// <returns>returns requested buffer else NULL</returns>
   inline TCHAR *AllocAsTChar(size_t sizeInBytes)
   {
      TCHAR *b = (TCHAR*)alloc(sizeInBytes);
      if (b == NULL)
         lastResult.HResult = ERROR_NOT_ENOUGH_MEMORY;
      return(b);
   }  // end of AllocAsTChar

   /// <summary>Release previously allocated memory</summary>
   /// <param name="buffer">previously allocated buffer</param>
   static inline void free(void *buffer)
   {
      if (buffer != NULL)
         ::free(buffer);
   }  // end of FreeMemory

   inline void Free(void *buffer)
   {
      if (buffer != NULL)
         Kif::Win32::Memory::free(buffer);
   }  // end of FreeMemory

   static inline size_t length(wchar_t *buffer)
   {
      if (buffer == NULL)
         return((size_t)-1);

      size_t slen = 0;
      HRESULT hr = StringCchLengthW(buffer,STRSAFE_MAX_CCH,&slen);
      if (hr != S_OK)
         slen = (size_t)-1;
      return(slen);
   }

   static inline size_t length(char *buffer)
   {
      if (buffer == NULL)
         return((size_t)-1);

      size_t slen = 0;
      HRESULT hr = StringCchLengthA(buffer,STRSAFE_MAX_CCH,&slen);
      if (hr != S_OK)
         slen = (size_t)-1;
      return(slen);
   }

    template<class T> static inline DWORD copy(
      T *target,DWORD lengthOfTarget,T *source,DWORD lengthOfSource)
   {
      if (lengthOfSource > lengthOfTarget)
         lengthOfSource = lengthOfTarget;
      DWORD i;
      for(i=0; i < lengthOfSource; i++,target++,source++)
         *target = *source;
      return(lengthOfSource);
   }  // end of copy

    static inline DWORD copyACharToWChar(
      wchar_t *target,DWORD lengthOfTarget,char *source,DWORD lengthOfSource)
   {
      if (lengthOfSource > lengthOfTarget)
         lengthOfSource = lengthOfTarget;
      DWORD i;
      for(i=0; i < lengthOfSource; i++,target++,source++)
         *target = *source;
      return(lengthOfSource);
   }  // end of copyACharToWChar

    template<class T> static inline void clear(
      T *target,DWORD lengthOfTarget,T clearValue)
   {
      DWORD i;
      for(i=0; i < lengthOfTarget; i++,target++)
         *target = clearValue;
   }  // end of clear

    template<class T> static inline size_t copy(
      T *target,size_t lengthOfTarget,T *source)
   {
      size_t lengthOfSource = (size_t)length(source);
      return(copy<T>(target,(DWORD)lengthOfTarget,source,(DWORD)lengthOfSource));
   }  // end of copy

   template<class T> static inline T *duplicate(
      T *string, DWORD stringLength)
   {
      if (string == NULL)
         return(0);

      T *outString = (T*)alloc((stringLength * sizeof(T)) + 1);
      if (outString == NULL)
         return(NULL);

      DWORD i;
      T *pOutStr = outString;
      for(i=0; i < stringLength; i++)
      {
         *pOutStr = *string;
         pOutStr++;
         string++;
      }

      *pOutStr = NULL;
      return(outString);
   }  // end of copy

   static inline TCHAR *duplicate(TCHAR *string)
   {
      TCHAR *outStr = NULL;
      if (string == NULL)
         return(NULL);

      size_t slen = 0;
      HRESULT hr = StringCchLength(string,STRSAFE_MAX_CCH,&slen);
      if (hr == S_OK)
         outStr = duplicate<TCHAR>(string,(DWORD)slen);
      return(outStr);
   }

}  ;  // end of String class

}  // end of Kif::Win32
}  // end of Kif

